﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;

namespace XFControls.XFPanels.XFPanelItems
{
    public interface IXFItemLoadingWorker
    {
        void DoWork();
    }

    public class WorkerEventArgs : EventArgs
    {
        public IXFItemLoadingWorker Worker { get; set; }

        public WorkerEventArgs(IXFItemLoadingWorker _worker)
        {
            Worker = _worker;
        }
    }

    public class XFItemLoading : IXFItem
    {
        private int height = 40;
        private IXFItemLoadingWorker _worker;
        private delegate void Invoker();
        private bool _hasWorked;

        #region IXFItem Members

        public XFItemType ItemType { get; set; }
        public Bitmap Buffer { get; set; }
        public delegate void WorkEventHandler(object sender, WorkerEventArgs e);
        public event WorkEventHandler WorkFinished;
        public XFItemState State { get; set; }
        public XFPanelBase Parent { get; set; }
        public XFItemStyle Style { get; set; }

        public XFItemLoading(IXFItemLoadingWorker worker, bool visible)
            : this(worker)
        {
            if (!visible)
                height = 0;
        }

        public XFItemLoading(IXFItemLoadingWorker worker)
        {
            _worker = worker;
            _hasWorked = false;

            Style = new XFItemStyle()
            {
                BackgroundColor = Color.RoyalBlue,
                DashStyleBottom = System.Drawing.Drawing2D.DashStyle.Dash,
                TextColor = Color.White,
                TextFont = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Bold)
            };
            ItemType = XFItemType.Display;
        }

        public int GetHeight()
        {
            return height;
        }

        public void ResetHeight() { }

        public void ItemPaint(System.Drawing.Graphics g, int x, int y)
        {
            if (!_hasWorked)
            {
                DoWork();
                _hasWorked = true;
            }
            int width = Screen.PrimaryScreen.WorkingArea.Width;
            
            XFControlUtils.DrawBackground(Style, g, x, y, width, height);
            XFControlUtils.DrawBoarders(Style, g, x, y, width, height);

            string loading = "Loading...";

            if (Parent != null)
            {
                width -= Parent.AlphaBarWidth;

                if (Parent.ScrollbarVisible)
                    width -= 5;
            }

            int xmid = width / 2;

            xmid -= (int)(g.MeasureString(loading, Style.TextFont).Width / 2);
            g.DrawString(loading, Style.TextFont, new SolidBrush(Style.TextColor), xmid, y + 2);
        }

        public XFItemClickResult GetClickResult()
        {
            return XFItemClickResult.Nothing;
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (Buffer != null)
                Buffer.Dispose();
            if (Style != null)
                Style.Dispose();

            Style = null;
            Buffer = null;
        }

        #endregion

        public void DoWork()
        {
            if (_hasWorked)
                return;

            _hasWorked = true;

            WaitCallback cb = new WaitCallback(doWork);
            ThreadPool.QueueUserWorkItem(cb);
        }

        private void doWork(object val)
        {
            if (_worker == null)
                return;

            Thread.CurrentThread.Priority = ThreadPriority.Lowest;
            _worker.DoWork();

            while (Parent.State != States.Idle)
                Thread.Sleep(100);

            if (WorkFinished != null)
                WorkFinished(this, new WorkerEventArgs(_worker));

            height = 0;

            if (Parent.InvokeRequired)
            {
                if (!Parent.IsDisposed)
                {
                    Parent.Invoke(new Action(() => { Parent.Reset(); Parent.Invalidate(); }));
                }
            }
            else
                Parent.Invalidate();
        }
    }
}
